iT邦幫忙

2024 iThome 鐵人賽

DAY 22
0
Kubernetes

K8s 資料庫管理系統系列 第 22

day 22 k8s 選課資料庫管理系統

  • 分享至 

  • xImage
  •  

今天是第二十二天我們可以寫一個k8s選課資料庫管理系統,以下是我的程式碼

設計概述

  1. 資料庫: 使用 MySQL 資料庫儲存課程資訊、學生選課等資料。
  2. 後端 API: 使用 Python Flask 框架處理與資料庫的互動。
  3. 前端: 使用簡單的 HTML/JavaScript 作為用戶介面,讓學生可以選課與查看已選課程。
  4. Kubernetes 部署: 使用 Kubernetes YAML 文件來描述資料庫、後端 API 和前端的部署與服務。

系統架構

  • MySQL 資料庫
    • Kubernetes 部署一個 MySQL Pod 並建立 Persistent Volume。
  • Flask 後端 API
    • Kubernetes 部署 Flask 應用,處理 CRUD 操作。
  • 前端服務
    • 部署前端應用(HTML + JavaScript),與 Flask API 互動。

1. MySQL 資料庫部署

創建一個 mysql-deployment.yaml 檔案來部署 MySQL。

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: mysql-pv-claim
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 10Gi
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: mysql
spec:
  selector:
    matchLabels:
      app: mysql
  template:
    metadata:
      labels:
        app: mysql
    spec:
      containers:
      - name: mysql
        image: mysql:5.7
        env:
        - name: MYSQL_ROOT_PASSWORD
          value: "password"
        - name: MYSQL_DATABASE
          value: "course_db"
        - name: MYSQL_USER
          value: "admin"
        - name: MYSQL_PASSWORD
          value: "password"
        ports:
        - containerPort: 3306
        volumeMounts:
        - name: mysql-persistent-storage
          mountPath: /var/lib/mysql
      volumes:
      - name: mysql-persistent-storage
        persistentVolumeClaim:
          claimName: mysql-pv-claim
---
apiVersion: v1
kind: Service
metadata:
  name: mysql
spec:
  ports:
    - port: 3306
  selector:
    app: mysql

2. Flask 後端 API 部署

創建一個簡單的 Flask API,與 MySQL 互動。首先,撰寫 app.py

from flask import Flask, request, jsonify
import mysql.connector

app = Flask(__name__)

def get_db_connection():
    conn = mysql.connector.connect(
        host='mysql',  # Kubernetes 服務名稱
        user='admin',
        password='password',
        database='course_db'
    )
    return conn

@app.route('/courses', methods=['GET'])
def get_courses():
    conn = get_db_connection()
    cursor = conn.cursor()
    cursor.execute('SELECT * FROM courses')
    courses = cursor.fetchall()
    cursor.close()
    conn.close()
    return jsonify(courses)

@app.route('/enroll', methods=['POST'])
def enroll_course():
    student_id = request.json['student_id']
    course_id = request.json['course_id']
    conn = get_db_connection()
    cursor = conn.cursor()
    cursor.execute('INSERT INTO enrollments (student_id, course_id) VALUES (%s, %s)', (student_id, course_id))
    conn.commit()
    cursor.close()
    conn.close()
    return 'Enrolled successfully!', 201

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5000)

創建 Dockerfile 來打包 Flask API:

FROM python:3.8-slim
WORKDIR /app
COPY requirements.txt requirements.txt
RUN pip install -r requirements.txt
COPY . .
CMD ["python", "app.py"]

requirements.txt:

Flask
mysql-connector-python

接著,創建 flask-deployment.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: flask-api
spec:
  selector:
    matchLabels:
      app: flask-api
  template:
    metadata:
      labels:
        app: flask-api
    spec:
      containers:
      - name: flask-api
        image: your-dockerhub-username/flask-api:latest
        ports:
        - containerPort: 5000
---
apiVersion: v1
kind: Service
metadata:
  name: flask-api
spec:
  ports:
    - port: 5000
  selector:
    app: flask-api

3. 前端服務

創建一個簡單的 index.html

<!DOCTYPE html>
<html>
<head>
    <title>選課系統</title>
</head>
<body>
    <h1>選課系統</h1>
    <form id="enrollForm">
        學生 ID: <input type="text" id="student_id"><br><br>
        課程 ID: <input type="text" id="course_id"><br><br>
        <button type="submit">選課</button>
    </form>

    <h2>已選課程</h2>
    <ul id="coursesList"></ul>

    <script>
        document.getElementById('enrollForm').onsubmit = function(event) {
            event.preventDefault();
            const studentId = document.getElementById('student_id').value;
            const courseId = document.getElementById('course_id').value;

            fetch('/enroll', {
                method: 'POST',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify({ student_id: studentId, course_id: courseId })
            })
            .then(response => response.text())
            .then(data => alert(data));
        };

        fetch('/courses')
            .then(response => response.json())
            .then(courses => {
                const coursesList = document.getElementById('coursesList');
                courses.forEach(course => {
                    const li = document.createElement('li');
                    li.textContent = `課程 ID: ${course[0]}, 課程名稱: ${course[1]}`;
                    coursesList.appendChild(li);
                });
            });
    </script>
</body>
</html>

將此前端部署在 Nginx 上,並創建 nginx-deployment.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: frontend
spec:
  selector:
    matchLabels:
      app: frontend
  template:
    metadata:
      labels:
        app: frontend
    spec:
      containers:
      - name: nginx
        image: nginx:latest
        volumeMounts:
        - name: html
          mountPath: /usr/share/nginx/html
      volumes:
      - name: html
        configMap:
          name: frontend-html
---
apiVersion: v1
kind: ConfigMap
metadata:
  name: frontend-html
data:
  index.html: |
    # (Paste index.html content here)
---
apiVersion: v1
kind: Service
metadata:
  name: frontend
spec:
  ports:
    - port: 80
  selector:
    app: frontend

4. 部署與運行

運行以下指令將部署所有服務:

kubectl apply -f mysql-deployment.yaml
kubectl apply -f flask-deployment.yaml
kubectl apply -f nginx-deployment.yaml

這樣,Kubernetes 就會運行選課系統,前端透過 Nginx 提供服務,後端 Flask API 處理選課請求,並與 MySQL 進行互動。

1. MySQL 資料庫部署

mysql-deployment.yaml 中,定義了 MySQL 資料庫的 Kubernetes 資源。這裡主要包含以下幾個部分:

PersistentVolumeClaim (PVC)

這段程式碼是用來申請一塊持久性存儲空間,用於 MySQL 存儲資料。

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: mysql-pv-claim
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 10Gi
  • PersistentVolumeClaim (PVC):它用來請求一塊 10GB 的持久存儲。這塊存儲將會被用來保存 MySQL 資料庫的數據,即使 Pod 被重啟,數據也不會丟失。
  • accessModes:設置為 ReadWriteOnce,表示這塊存儲可以被一個節點讀寫。

Deployment

MySQL 被打包成一個容器,這裡通過 Deployment 創建和管理 MySQL Pod。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: mysql
spec:
  selector:
    matchLabels:
      app: mysql
  template:
    metadata:
      labels:
        app: mysql
    spec:
      containers:
      - name: mysql
        image: mysql:5.7
        env:
        - name: MYSQL_ROOT_PASSWORD
          value: "password"
        - name: MYSQL_DATABASE
          value: "course_db"
        - name: MYSQL_USER
          value: "admin"
        - name: MYSQL_PASSWORD
          value: "password"
        ports:
        - containerPort: 3306
        volumeMounts:
        - name: mysql-persistent-storage
          mountPath: /var/lib/mysql
      volumes:
      - name: mysql-persistent-storage
        persistentVolumeClaim:
          claimName: mysql-pv-claim
  • Deployment:定義了 MySQL 容器的部署,管理 MySQL 的 Pod。
  • image: mysql:5.7:指定 MySQL 的 Docker 鏡像版本。
  • env:環境變量,用來設定 MySQL 的 root 密碼、資料庫名稱以及用戶憑證。
  • volumeMounts:將 PVC 持久化存儲掛載到容器內 /var/lib/mysql 目錄,這是 MySQL 存放數據的地方。

Service

apiVersion: v1
kind: Service
metadata:
  name: mysql
spec:
  ports:
    - port: 3306
  selector:
    app: mysql
  • Service:定義了如何對外暴露 MySQL 服務,讓其他 Pod(如 Flask API)可以通過 Kubernetes 的內部 DNS 名稱(mysql)來訪問資料庫。
  • port: 3306:指定 MySQL 使用的默認端口。

2. Flask API 後端

Flask API 是一個簡單的應用,它用來與 MySQL 資料庫互動,處理選課相關的操作。

Flask API (app.py)

引入庫與初始化 Flask 應用
from flask import Flask, request, jsonify
import mysql.connector

app = Flask(__name__)
  • Flask:引入 Flask 框架來處理 HTTP 請求。
  • mysql.connector:用來與 MySQL 資料庫連接。
  • app = Flask(__name__):初始化 Flask 應用,並且可以設定各種路由。
資料庫連接函數
def get_db_connection():
    conn = mysql.connector.connect(
        host='mysql',  # Kubernetes 服務名稱
        user='admin',
        password='password',
        database='course_db'
    )
    return conn
  • get_db_connection():用來建立與 MySQL 資料庫的連接。host='mysql' 表示 MySQL 是通過 Kubernetes 的內部 DNS 名稱來訪問。
  • userpassworddatabase:與 MySQL 連接所需的憑證。
課程查詢 API
@app.route('/courses', methods=['GET'])
def get_courses():
    conn = get_db_connection()
    cursor = conn.cursor()
    cursor.execute('SELECT * FROM courses')
    courses = cursor.fetchall()
    cursor.close()
    conn.close()
    return jsonify(courses)
  • @app.route('/courses', methods=['GET']):定義了一個 GET 請求的 API,URL 是 /courses。這個 API 會查詢所有課程。
  • cursor.execute('SELECT * FROM courses'):從 courses 資料表中查詢所有課程。
  • jsonify(courses):將查詢結果轉換成 JSON 格式,回傳給客戶端。
選課 API
@app.route('/enroll', methods=['POST'])
def enroll_course():
    student_id = request.json['student_id']
    course_id = request.json['course_id']
    conn = get_db_connection()
    cursor = conn.cursor()
    cursor.execute('INSERT INTO enrollments (student_id, course_id) VALUES (%s, %s)', (student_id, course_id))
    conn.commit()
    cursor.close()
    conn.close()
    return 'Enrolled successfully!', 201
  • @app.route('/enroll', methods=['POST']):定義了一個 POST 請求的 API,URL 是 /enroll。這個 API 用來讓學生選課。
  • student_idcourse_id:從請求中提取學生和課程的 ID。
  • INSERT INTO enrollments (student_id, course_id):將選課資訊插入到 enrollments 資料表中。

3. 前端 (index.html)

前端是一個簡單的 HTML 頁面,通過 JavaScript 與 Flask API 互動。

表單提交選課

<form id="enrollForm">
    學生 ID: <input type="text" id="student_id"><br><br>
    課程 ID: <input type="text" id="course_id"><br><br>
    <button type="submit">選課</button>
</form>
  • 表單允許用戶輸入學生 ID 和課程 ID,然後提交選課請求。

JavaScript 處理選課提交

document.getElementById('enrollForm').onsubmit = function(event) {
    event.preventDefault();
    const studentId = document.getElementById('student_id').value;
    const courseId = document.getElementById('course_id').value;

    fetch('/enroll', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ student_id: studentId, course_id: courseId })
    })
    .then(response => response.text())
    .then(data => alert(data));
};
  • onsubmit:攔截表單的提交動作。
  • fetch('/enroll', ...):向 /enroll API 發送 POST 請求,將選課資訊發送到伺服器。
  • JSON.stringify():將 JavaScript 對象轉換為 JSON 格式,發送至後端。

顯示已選課程

fetch('/courses')
    .then(response => response.json())
    .then(courses => {
        const coursesList = document.getElementById('coursesList');
        courses.forEach(course => {
            const li = document.createElement('li');
            li.textContent = `課程 ID: ${course[0]}, 課程名稱: ${course[1]}`;
            coursesList.appendChild(li);
        });
    });
  • fetch('/courses'):向 /courses API 發送 GET 請求,取得所有課程。
  • 將課程以列表形式顯示在網頁上。

4. Nginx 前端服務部署

前端的 HTML 和 JavaScript 被 Nginx 提供服務。

Nginx 部署 (nginx-deployment.yaml)

apiVersion: apps/v1
kind: Deployment
metadata:
  name: frontend
spec:
  selector:
    matchLabels:
      app: frontend
  template:
    metadata:
      labels:
        app: frontend
    spec:
      containers:
      - name: nginx
        image: nginx:latest
        volumeMounts:
        - name: html
          mountPath: /usr/share/nginx/html
      volumes:
      - name: html
        configMap:
          name: frontend-html
---
apiVersion: v1
kind: ConfigMap
metadata:
  name: frontend-html
data:


  index.html: |
    <!-- HTML 文件內容 -->
---
apiVersion: v1
kind: Service
metadata:
  name: frontend
spec:
  ports:
    - port: 80
  selector:
    app: frontend
  • nginx:用來提供靜態 HTML 文件服務。
  • ConfigMap:將 index.html 內容儲存在 ConfigMap 中,並掛載到 Nginx 容器的 /usr/share/nginx/html 目錄下。
  • Service:對外暴露 Nginx 服務,使用默認的 HTTP 端口 80。

總結

這個系統是一個簡單的選課系統,前端通過 Nginx 提供靜態頁面服務,後端 Flask API 用來處理資料庫操作,MySQL 資料庫存放課程和選課信息。每個部分都通過 Kubernetes 來管理和調度,使應用能夠在容器化環境中運行。


上一篇
day 21 K8s 微服務客戶喜好資料庫管理系統
下一篇
day 23 k8s 音樂庫資料庫管理系統
系列文
K8s 資料庫管理系統30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言